﻿// ===============================================================================
// ReferenceSchema.cs
// EOS Framework
// ===============================================================================
// Copyright (c) EOS Development Group. All rights reserved.
// ===============================================================================

namespace EOS.Framework.Contracts.Schema
{
    using System;
    using EOS.Framework.Tools;

    /// <summary>
    ///  Describes a reference between two tables.
    /// </summary>
    [Serializable]
    public class ReferenceSchema : IEquatable<ReferenceSchema>
    {
        #region Properties

        /// <summary>
        /// Reference to the child table.
        /// </summary>
        private TableSchema _childTable;

        /// <summary>
        /// Gets or sets the child table.
        /// </summary>
        /// <value>The child table.</value>
        public TableSchema ChildTable
        {
            get { return _childTable; }
            set { _childTable = value; }
        }

        /// <summary>
        /// Reference to the parent table.
        /// </summary>
        private TableSchema _parentTable;

        /// <summary>
        /// Gets or sets the parent table.
        /// </summary>
        /// <value>The parent table.</value>
        public TableSchema ParentTable
        {
            get { return _parentTable; }
            set { _parentTable = value; }
        }

        /// <summary>
        /// Indicates, if there will be done a cascade, when the child table changes.
        /// </summary>
        private bool _onUpdateCascade;

        /// <summary>
        /// Gets or sets a value indicating whether doing a cascade when child table changes.
        /// </summary>
        /// <value><c>true</c> if doing a cascade when child table is updated; otherwise, <c>false</c>.</value>
        public bool OnUpdateCascade
        {
            get { return _onUpdateCascade; }
            set { _onUpdateCascade = value; }
        }

        /// <summary>
        /// Indicates, if there will be done a cascade, when the child table is deleted.
        /// </summary>
        private bool _onDeleteCascade;

        /// <summary>
        /// Gets or sets a value indicating whether doing a cascade when child table is deleted.
        /// </summary>
        /// <value><c>true</c> if doing a cascade when child table is deleted; otherwise, <c>false</c>.</value>
        public bool OnDeleteCascade
        {
            get { return _onDeleteCascade; }
            set { _onDeleteCascade = value; }
        }

        /// <summary>
        /// List of joins.
        /// </summary>
        private ReferenceJoinCollection _joins;

        /// <summary>
        /// Gets the list of joins for this reference.
        /// </summary>
        /// <value>The joins.</value>
        public ReferenceJoinCollection Joins
        {
            get 
            {
                if (_joins == null)
                {
                    _joins = new ReferenceJoinCollection();
                }

                return _joins; 
            }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="ReferenceSchema"/> class.
        /// </summary>
        public ReferenceSchema()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ReferenceSchema"/> class
        /// with a parent table and a child table.
        /// </summary>
        /// <param name="parentTable">The parent table.</param>
        /// <param name="childTable">The child table.</param>
        public ReferenceSchema(TableSchema parentTable, TableSchema childTable)
        {
            this._parentTable = parentTable;
            this._childTable = childTable;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            return Equals(obj as ReferenceSchema);
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        public bool Equals(ReferenceSchema other)
        {
            if (other == null)
            {
                return false;
            }

            bool result = true;

            if (!Object.Equals(_childTable, other._childTable))
            {
                result = false;
            }

            if (!Object.Equals(_parentTable, other._parentTable))
            {
                result = false;
            }

            if (!Object.Equals(_onUpdateCascade, other._onUpdateCascade))
            {
                result = false;
            }

            if (!Object.Equals(_onDeleteCascade, other._onDeleteCascade))
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            int hashCode = _onDeleteCascade.GetHashCode() ^ _onUpdateCascade.GetHashCode();

            if (_childTable != null)
            {
                hashCode ^= _childTable.GetHashCode();
            }
            if (_parentTable!= null)
            {
                hashCode ^= _parentTable.GetHashCode();
            }
            if (_joins != null)
            {
                hashCode ^= _joins.CreateHashCode();
            }

            return hashCode;
        }
    }
}
